package com.vanguard.service;

import com.jcraft.jsch.SftpException;
import com.vanguard.utils.FileUtils;
import com.vanguard.utils.MD5Util;
import com.vanguard.utils.PropsUtil;
import com.vanguard.utils.SFTPUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Title: 合并文件业务
 * @Description:
 * @Author: vanguard
 * @Version: 1.0
 * @Date: 2018/11/28
 */
public class MergeService {

    private static Logger logger = LoggerFactory.getLogger(FileUtils.class);

    /**
     * 清算平台对账文件路径
     */
    private static String transFilePath;

    /**
     * 建行交易对账单文件路径
     */
    private static String shopFilePath;

    private static String contextPath;

    /**
     * 执行上传文件的时
     */
    private static int hour;

    /**
     * 执行上传文件的分
     */
    private static int minute;

    /**
     * 执行上传文件的秒
     */
    private static int second;

    private static long period;

    public static String WEIXIN_PAY_TYPE = "微信";

    private ScheduledExecutorService scheduledExecutorService;

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public MergeService() {
        scheduledExecutorService = Executors.newScheduledThreadPool(2);
    }

    static {
        loadProperties();
    }

    /**
     * 加载配置文件
     * @author vanguard
     * @date  10:32
     * @param
     * @return void
     */
    private static void loadProperties() {
        PropsUtil.loadProps("config.properties");
        transFilePath = PropsUtil.getString("transFilePath");
        shopFilePath = PropsUtil.getString("shopFilePath");
        contextPath = PropsUtil.getString("contextPath");
        String[] uploadTimes = PropsUtil.getString("uploadTime").split("_");
        hour = Integer.parseInt(uploadTimes[0]);
        minute = Integer.parseInt(uploadTimes[1]);
        second = Integer.parseInt(uploadTimes[0]);
        period = Long.valueOf(PropsUtil.getString(("periodTime")));
    }

    /**
     * 读取清算平台对账单文件
     */
    public Map<String, String> readTransFile() {
        Map<String, String> data = new HashMap<>();
        long transPos = 0L;
        int transNum = 1000;
        File transFile = new File(transFilePath);

        logger.info("开始读取清算平台对账文件:" + dateFormat.format(new Date()));
        //循环读取遍历对账文件
        while(true) {
            //读取清算平台对账文件
            Map<String, Object> transRes = FileUtils.bufferedRandomAccessFileReadLine(transFile, "UTF-8", transPos, transNum);
            if(transRes == null || transRes.size() != 2) {
                logger.error("清算平台对账文件不存在！");
                return null;
            }
            //获得读取到的list集合
            List<String> transPins = (List<String>) transRes.get("pins");
            //获得当前读取文件的偏移量
            transPos = (long) transRes.get("pos");
            if (transPins != null && transPins.size() > 0) {
                //遍历读取的list集合，去和建行交易对账文件比较
                for(String line : transPins) {
                    String[] transFields = line.split("\\|");
                    //读出支付银行
                    String payBank = transFields[6];
                    //不是微信支付跳过
                    if(!payBank.equals(WEIXIN_PAY_TYPE)) {
                        continue;
                    }
                    //读取出清算平台流水号
                    String serialId = transFields[4];
                    //以平台流水号为key，所对应的一行数据为value，存入map中
                    data.put(serialId, line);
                }
                if (transPins.size() < transNum) {
                    break;
                }
            } else {
                break;
            }
        }
        return data;
    }

    /**
     * 读取建行交易对账单数据
     * @return Map
     */
    public Map<String, String> readShopFile() {
        Map<String, String> data = new HashMap<>();
        long shopPos = 0L;
        int shopNum = 1000;
        File shopFile = new File(shopFilePath);
        logger.info("开始读取建行交易对账文件:" + dateFormat.format(new Date()));
        while(true) {
            //读取建行交易对账文件
            Map<String, Object> shopRes = FileUtils.bufferedRandomAccessFileReadLine(shopFile, "UTF-8", shopPos, shopNum);
            if(shopRes == null || shopRes.size() != 2) {
                logger.error("建行交易对账文件不存在！");
                return null;
            }
            List<String> shopPins = (List<String>) shopRes.get("pins");
            shopPos = (long) shopRes.get("pos");
            if (shopPins != null && shopPins.size() > 0) {
                //遍历读取建行交易对账文件list集合
                for(String line : shopPins) {
                    if(!line.contains("\t")) {
                        continue;
                    }
                    String[] shopFields = line.split("\t");
                    //读取订单号
                    String orderId = shopFields[4];
                    //以订单号为key，所对应的一行数据为value，放入map中
                    data.put(orderId, line);
                }
                if (shopPins.size() < shopNum) {
                    break;
                }
            } else {
                break;
            }
        }
        return data;
    }


    /**
     * 合并清算平台对账单数据和建行交易对账单数据，并写入文件
     * @param transMap
     * @param shopMap
     * return 生成文件的路径
     */
    public String merge(Map<String, String> transMap, Map<String, String> shopMap) {
        //如果清算平台对账数据或者建行交易对账数据不存在
        if(transMap == null || shopMap == null) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String now = format.format(new Date());
        String fileName = "ycshell_payorder_" + now + ".txt";
        File file = new File(contextPath, fileName);
        try {
            //生成目录，如果文件不存在，则创建文件
            if ((FileUtils.createDir(contextPath)) && (!file.exists())) {
                file.createNewFile();
            }

            //遍历清算平台对账单map数据
            for(Map.Entry<String, String> entry : transMap.entrySet()) {
                String orderId = entry.getKey();
                //判断建行交易对账时数据map中有清算平台对账数据的流水号
                if(shopMap.containsKey(orderId)) {
                    String transLine = entry.getValue();
                    String[] transFields = transLine.split("\\|");
                    //找到建行交易对账单中对应的数据
                    String shopLine = shopMap.get(orderId);
                    String[] shopFields = shopLine.split("\\t");
                    //商户号
                    String merchantId = transFields[1];
                    //商户订单号
                    String merchantOrderId = transFields[3];
                    //订单金额*100（单位：分）
                    BigDecimal orderAccount = new BigDecimal(shopFields[8]).multiply(new BigDecimal(100));
                    //交易时间
                    String businessTime = shopFields[0];
                    //微信openId，并使用md5加密
                    String openId = MD5Util.string2MD5(shopFields[7]);
                    //备注
                    String remark = shopFields[20];
                    StringBuffer buffer = new StringBuffer();

                    //利用StringBuffer拼接数据
                    //商户号
                    buffer.append(merchantId).append("|");
                    //商户订单号
                    buffer.append(merchantOrderId).append("|");
                    //平台订单号
                    buffer.append(orderId).append("|");
                    //订单金额
                    buffer.append(orderAccount).append("|");
                    //交易时间
                    buffer.append(businessTime).append("|");
                    //openId
                    buffer.append(openId).append("|");
                    //备注
                    buffer.append(remark).append("\r\n");
                    logger.info("写入数据到文件中，" + buffer.toString());
                    //写入文件中
                    FileUtils.append(file, "UTF-8", buffer.toString());
                    buffer.setLength(0);
                }
            }
            logger.info("写入文件完成:" + dateFormat.format(new Date()));
        } catch (Exception e) {
            logger.error("文件创建失败!");
        }
        String filePath = contextPath + File.separator + fileName;
        return filePath;
    }

    /**
     * 指定时间将文件上传到sftp服务器中
     * @param filePath
     */
    public void autoUploadSftp(final String filePath) {
        Calendar calendar = Calendar.getInstance();
        // 控制时
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        // 控制分
        calendar.set(Calendar.MINUTE, minute);
        // 控制秒
        calendar.set(Calendar.SECOND, second);

        // 得出执行任务的时间
        Date date = calendar.getTime();
        //获得推迟秒数
        long time = (date.getTime() - System.currentTimeMillis())/1000;

        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                uploadSftp(filePath);
            }
        }, time, period, TimeUnit.SECONDS);
    }

    /**
     * 上传到sftp服务器
     * @param filePath
     */
    public void uploadSftp(String filePath) {
        logger.info("开始执行上传文件:" + dateFormat.format(new Date()));
        File file = new File(filePath);
        //生成上传文件名和路径
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String now = format.format(new Date());
        String fileName = "ycshell_payorder_" + now + ".txt";
        String path = "/ycshell";
        SFTPUtil ftp = new SFTPUtil();
        ftp.login();
        try {
            ftp.upload(path, fileName, new FileInputStream(file));
        } catch (SftpException e) {
            logger.error("连接sftp服务器失败");
        } catch (FileNotFoundException e) {
            logger.error("找不到生成的文件");
        } finally {
            ftp.logout();
        }
        logger.info("上传文件完成:" + dateFormat.format(new Date()));
    }
}
